﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using BoneSystem.Extensions.Annotations;

namespace BoneSystem.Extensions.Form
{
    public class FormLayout<T, TProperty>: Component
    {
        private FocusManager _focusManager;

        private FocusManager FocusManager
        {
            get { return _focusManager ?? (_focusManager = new FocusManager()); }
            set { _focusManager = value; }
        }

        public FormLayout()
        {
            InputAttributes = new List<InputAttribute>();
            Components = new Dictionary<int, object>();
        }
        public HtmlHelper<T> HtmlHelper { get; set; }
        public new FormSettings Settings { get; set; }
        private Dictionary<int, object> Components { get; set; } 
        public IList<InputAttribute> InputAttributes { get; set; }

        public FormLayout<T, TProperty> BsAddInput(InputAttribute input)
        {
            
            if (!string.IsNullOrEmpty(input.Name))
            {
                if (Settings.AngularApp &&
                    Settings.AngularFormSettings != null &&
                    !string.IsNullOrEmpty(Settings.AngularFormSettings.ObjectDataModel))
                {
                    input.NgModel = Settings.AngularFormSettings.ObjectDataModel + "." + input.Name;
                }
            }

            FocusManager.AddFocusItem(new FocusManagerItem()
            {
                ControlId = input.Id,
            }, Settings.Name);
            InputAttributes.Add(input);
            AddComponente(input);
            return this;
        }

        public void RederHtmlString()
        {
            var tagScript = GetTagScript();
            var tagLayout = GetLayoutTable();
            String t = tagScript.ToString(TagRenderMode.Normal);
            var ret = new MvcHtmlString(tagScript.ToString(TagRenderMode.Normal) +
                          tagLayout.ToString(TagRenderMode.Normal));
            HtmlHelper.ViewContext.Writer.WriteLine(ret);
        }

        public void AddComponente(object component)
        {
            var index = 0;
            if (Components.Keys.Count > 0)
            {
                index = Components.Keys.Max(x => x) + 1;
            }
            Components.Add(index, component);
        }

      

        private AngularTag GetLayoutTable()
        {
            var divApp = new AngularTag("div");
            
            divApp.AddDirective("ng-app");
            if (Settings.AngularApp)
            {
                var msg = "Se a propriedade AngularApp estiver definida como 'True'" +
                          " deve-se especificar uma as propriedades da aplicação angularjs";
                if (Settings.AngularFormSettings == null)
                {
                    throw new Exception(msg);
                }
                if (string.IsNullOrEmpty(Settings.AngularFormSettings.NgController))
                {
                    throw new Exception("Ao criar uma aplicação angularjs deve-se especificar o controller" +
                                        " da da mesma.");
                }

                //divApp.Attributes["ng-controller"] = Settings.AngularFormSettings.NgController;
            }
            var tagLayout = new TagBuilder("table");
            tagLayout.Attributes["width"] =Settings.Width.ToString(CultureInfo.InvariantCulture);

            if (InputAttributes.Count > 0)
            {
                // Armazena todas as tags de linha.
                var rows = new List<TagBuilder>();
                var colCount = InputAttributes.Sum(x => x.ColSpan);
                var currentColumn = 1;
                var currentComponentIndex = 0;
                // Obtém a quantidade de colunas necessárias para a tabela.
                var rowCount = (colCount / Settings.ColCount) % InputAttributes.Count;

                var row = new TagBuilder("tr");
                var components = Components.Values.ToArray();
                

                // Verifica se deve ser adicionada uma linha para comportar os componentes.
                foreach (var componentObject in components)
                {

                    if (componentObject is InputAttribute)
                    {
                        var inputAttribute = (InputAttribute) componentObject;
                        var changeRow = currentColumn + inputAttribute.ColSpan > Settings.ColCount;
                        if (changeRow)
                        {

                            var col = new TagBuilder("td");
                            col.Attributes["colspan"] = inputAttribute.ColSpan.ToString(CultureInfo.InvariantCulture);
                            col.InnerHtml += inputAttribute.ToMvcHtmlString();
                            row.InnerHtml += new MvcHtmlString(col.ToString(TagRenderMode.Normal));
                            rows.Add(row);
                            row = new TagBuilder("tr");
                            currentColumn = 1;
                        }
                        else
                        {
                            if (currentComponentIndex == components.Length - 1)
                            {
                                row = new TagBuilder("tr");
                                var col = new TagBuilder("td");
                                col.Attributes["colspan"] = inputAttribute.ColSpan.ToString(CultureInfo.InvariantCulture);
                                col.InnerHtml += inputAttribute.ToMvcHtmlString();
                                row.InnerHtml += new MvcHtmlString(col.ToString(TagRenderMode.Normal));
                                rows.Add(row);
                            }
                            else
                            {
                                var col = new TagBuilder("td");
                                col.Attributes["colspan"] = inputAttribute.ColSpan.ToString(CultureInfo.InvariantCulture);
                                col.InnerHtml += inputAttribute.ToMvcHtmlString();
                                row.InnerHtml += new MvcHtmlString(col.ToString(TagRenderMode.Normal));
                                currentColumn += inputAttribute.ColSpan;
                            }
                            
                        }
                    }else if (componentObject is Component)
                    {
                        var component = (Component) componentObject;
                        var col = new TagBuilder("td");
                        col.Attributes["colspan"] = component.Settings.ColSpan.ToString(CultureInfo.InvariantCulture);
                        col.InnerHtml += component.GetHtmlString();
                        row.InnerHtml += new MvcHtmlString(col.ToString(TagRenderMode.Normal));
                        currentColumn += component.Settings.ColSpan;
                    }
                    currentComponentIndex += 1;
                }
                foreach (var rowInput in rows)
                {
                    tagLayout.InnerHtml += new MvcHtmlString(rowInput.ToString(TagRenderMode.Normal));
                }
            }
            divApp.InnerHtml = new MvcHtmlString(tagLayout.ToString(TagRenderMode.Normal)).ToHtmlString();
            return divApp;
        }

        private TagBuilder GetTagScript()
        {
            var tagScript = new TagBuilder("script");
            tagScript.Attributes["type"] = "text/javascript";
            tagScript.Attributes["language"] = "javascript";
            var script = new StringBuilder();
            var events = new StringBuilder();
            foreach (var inputAttribute in InputAttributes)
            {
                script.Append(inputAttribute.GetScripts());
                events.Append(inputAttribute.GetEvents());
            }
            tagScript.InnerHtml += script + "$(function(){" + FocusManager.End(Settings.Name) + 
                new HtmlString(events.ToString()) + "});";
            return tagScript;
        }

        public override MvcHtmlString GetHtmlString()
        {
            return new MvcHtmlString(GetLayoutTable().ToString(TagRenderMode.Normal));
        }

        internal override AngularTag GetTag()
        {
            var tagScript = GetTagScript();
            var tagLayout = GetLayoutTable();
            String t = tagScript.ToString(TagRenderMode.Normal);
            var divForm = new AngularTag("div");

            divForm.InnerHtml = tagScript.ToString(TagRenderMode.Normal) +
                          tagLayout.ToString(TagRenderMode.Normal);
            return divForm;
        }
    }
}
